//-------------------------------------------------------------------
//	Copyright (c) 2010-2011  Zhirnov Andrey
//	This file is part of the "UXGEN_ResourceConverter" project.
//	See copyright notice in "Converter.h".
//-------------------------------------------------------------------

#include "MeshConverters.h"
#include "..\\..\\Core\\CConverter.h"



inline string ToString(float f)
{
	return string().FormatF( f, 0x3, false, false );
}

inline string ToString(const vec2 &v)
{
	return (string() << string().FormatF( v.x, 0x3, false, false ) << ", "
					 << string().FormatF( v.y, 0x3, false, false ) );
}

inline string ToString(const vec3 &v)
{
	return (string() << string().FormatF( v.x, 0x3, false, false ) << ", "
					 << string().FormatF( v.y, 0x3, false, false ) << ", "
					 << string().FormatF( v.z, 0x3, false, false ) );
}

inline string ToString(const vec4 &v)
{
	return (string() << string().FormatF( v.x, 0x3, false, false ) << ", "
					 << string().FormatF( v.y, 0x3, false, false ) << ", "
					 << string().FormatF( v.z, 0x3, false, false ) << ", "
					 << string().FormatF( v.w, 0x3, false, false ) );
}

inline string ToString3(const color4f &sColor)
{
	return (string() << string().FormatF( sColor.r, 0x3, false, false ) << ", "
					 << string().FormatF( sColor.g, 0x3, false, false ) << ", "
					 << string().FormatF( sColor.b, 0x3, false, false ) );
}

inline string ToString(const color4f &sColor)
{
	return (string() << string().FormatF( sColor.r, 0x3, false, false ) << ", "
					 << string().FormatF( sColor.g, 0x3, false, false ) << ", "
					 << string().FormatF( sColor.b, 0x3, false, false ) << ", "
					 << string().FormatF( sColor.a, 0x3, false, false ) );
}




struct TMtrConverter
{
	enum E_MTR_TYPE
	{
		MTR_UNKNOWN			= 0,
		MTR_DIFFUSE_MAP		= 0x00000001,
		MTR_NORMAL_MAP		= 0x00000002,
		MTR_HEIGHT_MAP		= 0x00000004,
		MTR_OPACITY_MAP		= 0x00000008,
		MTR_EMISSION_MAP	= 0x00000010,
		MTR_SPECULAR_MAP	= 0x00000020,
		MTR_AMBIENT_MAP		= 0x00000040,
		MTR_REFLECTION_MAP	= 0x00000080,

		MTR_MAPS_PRIORITY_0	= 0x0000000F,
		MTR_MAPS_PRIORITY_1	= 0x000000FF,
		MTR_MAPS_PRIORITY_2	= 0x00000FFF,
		MTR_MAPS_PRIORITY_3	= 0x0000FFFF,
	};

	typedef bool (TMtrConverter:: *PConvProc_t)(const TMaterial &);

	struct TLink
	{
		PConvProc_t				pProc;
		uint					eType;
	};

	static const TLink		s_aLinks[];
	static const uint		s_uLinksCount;

	///
	IFilePtr				pFile;
	string					sData;
	
	///
	TMtrConverter();
	~TMtrConverter();

	bool Create(const string &sFileName);
	bool ChooseTypeAndConvert(const TMaterial &sMtr);
	bool Save();

	///
	bool _ToNoTextured(const TMaterial &sMtr);
	bool _ToDiffuse(const TMaterial &sMtr);
	bool _ToNormal(const TMaterial &sMtr);
	bool _ToParallax(const TMaterial &sMtr);
	bool _ToDisplace(const TMaterial &sMtr);

	bool _Choose(uint eType, PConvProc_t &pProc);
	void _WriteHeader(const string &sMtrName);
	void _BuildMtrPass(e_program::type eProgType, e_render_layer::type eLayer,
					   e_program_data::type eProgData, uint8 uLOD, const string &sUBOData,
					   const string &sTextures, const TGLRenderState &sRS, bool bRS);
};



const TMtrConverter::TLink	TMtrConverter::s_aLinks[] = {
	{ &TMtrConverter::_ToNoTextured,	MTR_UNKNOWN },
	{ &TMtrConverter::_ToDiffuse,		MTR_DIFFUSE_MAP },
	{ &TMtrConverter::_ToNormal,		MTR_DIFFUSE_MAP | MTR_NORMAL_MAP },
	{ &TMtrConverter::_ToParallax,		MTR_DIFFUSE_MAP | MTR_NORMAL_MAP | MTR_HEIGHT_MAP },
	{ &TMtrConverter::_ToDisplace,		MTR_DIFFUSE_MAP | MTR_HEIGHT_MAP }
};
const uint					TMtrConverter::s_uLinksCount = COUNT_OF( s_aLinks );



bool SaveMaterial(const string &sFileName, const TMaterial &sMtr)
{
	TMtrConverter	s_conv;
	return s_conv.Create( sFileName ) && s_conv.ChooseTypeAndConvert( sMtr ) && s_conv.Save();
}




	
	
TMtrConverter::TMtrConverter()
{
}


TMtrConverter::~TMtrConverter()
{
}


bool TMtrConverter::Create(const string &sFileName)
{
	sData.Clear();
	pFile = nullptr;

	return CORE->LoadFile( sFileName.cstr(), pFile, e_file_open_flags::DEF_WRITE ) == S_OK;
}


bool TMtrConverter::Save()
{
	bool	ret = false;

	if ( pFile != nullptr )
	{
		ret = pFile->WriteS( sData.ptr(), sData.Size()-1 );
		
		sData.Clear();
		pFile = nullptr;
	}
	return ret;
}


bool TMtrConverter::ChooseTypeAndConvert(const TMaterial &sMtr)
{
	PConvProc_t	p_proc	= nullptr;
	uint		u_type	= MTR_UNKNOWN;

	u_type |= sMtr.sAmbient.sMapFileName.Empty()	? 0 : MTR_AMBIENT_MAP;
	u_type |= sMtr.sNormalMap.Empty()				? 0 : MTR_NORMAL_MAP;
	u_type |= sMtr.sDiffuse.sMapFileName.Empty()	? 0 : MTR_DIFFUSE_MAP;
	u_type |= sMtr.sEmission.sMapFileName.Empty()	? 0 : MTR_EMISSION_MAP;
	u_type |= sMtr.sHeightMap.Empty()				? 0 : MTR_HEIGHT_MAP;
	u_type |= sMtr.sOpacityMap.Empty()				? 0 : MTR_OPACITY_MAP;
	u_type |= sMtr.sReflectionMap.Empty()			? 0 : MTR_REFLECTION_MAP;
	u_type |= sMtr.sSpecular.sMapFileName.Empty()	? 0 : MTR_SPECULAR_MAP;

	if ( !_Choose( u_type & MTR_MAPS_PRIORITY_3, p_proc ) )
		if ( !_Choose( u_type & MTR_MAPS_PRIORITY_2, p_proc ) )
			if ( !_Choose( u_type & MTR_MAPS_PRIORITY_1, p_proc ) )
				if ( !_Choose( u_type & MTR_MAPS_PRIORITY_0, p_proc ) )
					return false;

	return (this->*p_proc)( sMtr );
}


bool TMtrConverter::_Choose(uint eType, PConvProc_t &pProc)
{
	for (uint i = 0; i < s_uLinksCount; ++i)
	{
		if ( s_aLinks[i].eType == eType ) {
			pProc = s_aLinks[i].pProc;
			return true;
		}
	}
	return false;
}


bool TMtrConverter::_ToNoTextured(const TMaterial &sMtr)
{
	_WriteHeader( sMtr.sName );

	string	ubo_data,
			textures;

	ubo_data
		<< "			" << ToString( sMtr.sAmbient.sColor )  << ",	// ambient\n"
		<< "			" << ToString( sMtr.sDiffuse.sColor )  << ",	// diffuse\n"
		<< "			" << ToString( sMtr.sSpecular.sColor ) << ",	// specular\n"
		<< "			" << ToString3( sMtr.sEmission.sColor ) << ",		// emission\n"
		<< "			" << ToString( sMtr.fShininess ) << "						// shininess\n";

	_BuildMtrPass( e_program::UNTEXTURED, e_render_layer::OPAQUE_0, e_program_data::MATERIAL, 0, ubo_data, textures, sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::DEPTH_ONLY_0, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::SINGLE_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::LAYERED_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );

	sData << "}\n";
	return true;
}


bool TMtrConverter::_ToDiffuse(const TMaterial &sMtr)
{
	_WriteHeader( sMtr.sName );

	string	ubo_data,
			textures,
			tex_file = sMtr.sDiffuse.sMapFileName;

	String::CutFileExt( tex_file );

	ubo_data
		<< "			" << ToString( sMtr.sAmbient.sColor )  << ",	// ambient\n"
		<< "			" << ToString( sMtr.sDiffuse.sColor )  << ",	// diffuse\n"
		<< "			" << ToString( sMtr.sSpecular.sColor ) << ",	// specular\n"
		<< "			" << ToString3( sMtr.sEmission.sColor ) << ",		// emission\n"
		<< "			" << ToString( sMtr.fShininess ) << "						// shininess\n";

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.DIFFUSE }\n";
	textures.ChangeChars( '\\', '/' );

	_BuildMtrPass( e_program::DIFFUSE, e_render_layer::OPAQUE_0, e_program_data::MATERIAL, 0, ubo_data, textures, sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::DEPTH_ONLY_0, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::SINGLE_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::LAYERED_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );

	sData << "}\n";
	return true;
}


bool TMtrConverter::_ToNormal(const TMaterial &sMtr)
{
	_WriteHeader( sMtr.sName );

	string	ubo_data,
			textures,
			tex_file;

	ubo_data
		<< "			" << ToString( sMtr.sAmbient.sColor )  << ",	// ambient\n"
		<< "			" << ToString( sMtr.sDiffuse.sColor )  << ",	// diffuse\n"
		<< "			" << ToString( sMtr.sSpecular.sColor ) << ",	// specular\n"
		<< "			" << ToString3( sMtr.sEmission.sColor ) << ",		// emission\n"
		<< "			" << ToString( sMtr.fShininess ) << "						// shininess\n";

	tex_file = sMtr.sDiffuse.sMapFileName;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.DIFFUSE },\n";
	
	tex_file = sMtr.sNormalMap;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.NORMAL }\n";
	textures.ChangeChars( '\\', '/' );


	_BuildMtrPass( e_program::NORMAL, e_render_layer::OPAQUE_0, e_program_data::MATERIAL, 0, ubo_data, textures, sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::DEPTH_ONLY_0, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::SINGLE_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::LAYERED_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );

	sData << "}\n";
	return true;
}


bool TMtrConverter::_ToParallax(const TMaterial &sMtr)
{
	_WriteHeader( sMtr.sName );

	string	ubo_data,
			textures,
			tex_file;

	ubo_data
		<< "			" << ToString( sMtr.sAmbient.sColor )  << ",	// ambient\n"
		<< "			" << ToString( sMtr.sDiffuse.sColor )  << ",	// diffuse\n"
		<< "			" << ToString( sMtr.sSpecular.sColor ) << ",	// specular\n"
		<< "			" << ToString3( sMtr.sEmission.sColor ) << ",		// emission\n"
		<< "			" << ToString( sMtr.fShininess ) << "						// shininess\n";
	
	tex_file = sMtr.sDiffuse.sMapFileName;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.DIFFUSE },\n";
	
	tex_file = sMtr.sNormalMap;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.NORMAL },\n";
	
	tex_file = sMtr.sHeightMap;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.HEIGHT }\n";
	textures.ChangeChars( '\\', '/' );

	_BuildMtrPass( e_program::PARALLAX, e_render_layer::OPAQUE_0, e_program_data::MATERIAL, 0, ubo_data, textures, sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::DEPTH_ONLY_0, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::SINGLE_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::LAYERED_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );

	sData << "}\n";
	return true;
}


bool TMtrConverter::_ToDisplace(const TMaterial &sMtr)
{
	_WriteHeader( sMtr.sName );

	string	ubo_data,
			textures,
			tex_file;

	ubo_data
		<< "			" << ToString( sMtr.sAmbient.sColor )  << ",	// ambient\n"
		<< "			" << ToString( sMtr.sDiffuse.sColor )  << ",	// diffuse\n"
		<< "			" << ToString( sMtr.sSpecular.sColor ) << ",	// specular\n"
		<< "			" << ToString3( sMtr.sEmission.sColor ) << ",		// emission\n"
		<< "			" << ToString( sMtr.fShininess ) << "						// shininess\n";

	tex_file = sMtr.sDiffuse.sMapFileName;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.DIFFUSE },\n";
	
	tex_file = sMtr.sHeightMap;
	String::CutFileExt( tex_file );

	textures
		<< "			{ \"" << tex_file << ".tex\", e_tex_flags.DEFAULT_3D, e_texture.HEIGHT }\n";
	textures.ChangeChars( '\\', '/' );

	_BuildMtrPass( e_program::DISPLACEMENT, e_render_layer::OPAQUE_0, e_program_data::MATERIAL, 0, ubo_data, textures, sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::DEPTH_ONLY_0, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::SINGLE_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );
	sData << "\n";
	_BuildMtrPass( e_program::DEPTH, e_render_layer::LAYERED_SHADOW_MAP, e_program_data::UNKNOWN, 0, string(), string(), sMtr.sStates, sMtr.bRSEnabled );

	sData << "}\n";
	return true;
}


void TMtrConverter::_WriteHeader(const string &sMtrName)
{
	string	path;
	bool	b_find_path = false;
	
	if ( String::GetFilePath( pFile->GetName().cstr(), path ) )
	{
		path << '\\';

		uint	u_depth = 0;
		string	temp;

		for (; u_depth < 10; ++u_depth)
		{
			temp << "..\\";

			if ( CORE->FileExist( (path + temp + "material_include.ocf").cstr() ) )
			{
				path = temp;
				b_find_path = true;
				break;
			}
		}
	}

	if ( !b_find_path )
		path.Clear();

	sData << "include \"" << path << "material_include.ocf\"\n\n";
	sData << "object Material(\"" << sMtrName << "\")\n{\n";
}


const char * _GetBlendFunc(gl_blend_func::type eType)
{
	struct TBlendFunc
	{
		const char	*		pName;
		gl_blend_func::type	eType;
	};

#define DEF_BLEND_FUNC( _type )		{ TOSTRING( _type ), gl_blend_func::_type }
	static const TBlendFunc	s_aBlendFuncs[] = {
		DEF_BLEND_FUNC( ZERO ),
		DEF_BLEND_FUNC( ONE ),
		DEF_BLEND_FUNC( SRC_COLOR ),
		DEF_BLEND_FUNC( ONE_MINUS_SRC_COLOR ),
		DEF_BLEND_FUNC( DST_COLOR ),
		DEF_BLEND_FUNC( ONE_MINUS_DST_COLOR ),
		DEF_BLEND_FUNC( SRC_ALPHA ),
		DEF_BLEND_FUNC( ONE_MINUS_SRC_ALPHA ),
		DEF_BLEND_FUNC( DST_ALPHA ),
		DEF_BLEND_FUNC( ONE_MINUS_DST_ALPHA ),
		DEF_BLEND_FUNC( CONST_COLOR ),
		DEF_BLEND_FUNC( ONE_MINUS_CONST_COLOR ),
		DEF_BLEND_FUNC( CONST_ALPHA ),
		DEF_BLEND_FUNC( ONE_MINUS_CONST_ALPHA ),
		DEF_BLEND_FUNC( SRC_ALPHA_SATURATE ),
		DEF_BLEND_FUNC( SRC1_COLOR ),
		DEF_BLEND_FUNC( SRC1_ALPHA ),
		DEF_BLEND_FUNC( ONE_MINUS_SRC1_COLOR ),
		DEF_BLEND_FUNC( ONE_MINUS_SRC1_ALPHA )
	};
	static const uint		s_uBlendFuncsCount = COUNT_OF( s_aBlendFuncs );
	static char				s_aTemp[64];
#undef DEF_BLEND_FUNC

	for (uint i = 0; i < s_uBlendFuncsCount; ++i) {
		if ( s_aBlendFuncs[i].eType == eType )
			return s_aBlendFuncs[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetBlendEquation(gl_blend_equation::type eType)
{
	struct TBlendEq
	{
		const char	*			pName;
		gl_blend_equation::type	eType;
	};

#define DEF_BLEND_EQUATION( _type )		{ TOSTRING( _type ), gl_blend_equation::_type }
	static const TBlendEq	s_aBlendEq[] = {
		DEF_BLEND_EQUATION( ADD ),
		DEF_BLEND_EQUATION( SUB ),
		DEF_BLEND_EQUATION( REV_SUB ),
		DEF_BLEND_EQUATION( MIN ),
		DEF_BLEND_EQUATION( MAX )
	};
	static const uint		s_uBlendEqCount = COUNT_OF( s_aBlendEq );
	static char				s_aTemp[64];
#undef  DEF_BLEND_EQUATION

	for (uint i = 0; i < s_uBlendEqCount; ++i) {
		if ( s_aBlendEq[i].eType == eType )
			return s_aBlendEq[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetColorMask(e_color_mask::type eType)
{
	struct TColorMask
	{
		const char	*		pName;
		e_color_mask::type	eType;
	};

#define DEF_COLOR_MASK( _type )		{ TOSTRING( _type ), e_color_mask::_type }
	static const TColorMask	s_aColorMasks[] = {
		DEF_COLOR_MASK( NONE ),
		DEF_COLOR_MASK( R ),
		DEF_COLOR_MASK( G ),
		DEF_COLOR_MASK( B ),
		DEF_COLOR_MASK( A ),
		DEF_COLOR_MASK( RGBA ),
		DEF_COLOR_MASK( RG ),
		DEF_COLOR_MASK( RB ),
		DEF_COLOR_MASK( RGB ),
		DEF_COLOR_MASK( GB ),
		DEF_COLOR_MASK( GA ),
		DEF_COLOR_MASK( GBA ),
		DEF_COLOR_MASK( BA )
	};
	static const uint		s_uColorMasksCount = COUNT_OF( s_aColorMasks );
	static char				s_aTemp[64];
#undef  DEF_COLOR_MASK

	for (uint i = 0; i < s_uColorMasksCount; ++i) {
		if ( s_aColorMasks[i].eType == eType )
			return s_aColorMasks[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetCompareMode(gl_compare_mode::type eType)
{
	struct TCompareMode
	{
		const char	*			pName;
		gl_compare_mode::type	eType;
	};

#define DEF_COMPARE_MODE( _type )		{ TOSTRING( _type ), gl_compare_mode::_type }
	static const TCompareMode	s_aCompareModes[] = {
		DEF_COMPARE_MODE( NEVER ),
		DEF_COMPARE_MODE( LESS ),
		DEF_COMPARE_MODE( EQUAL ),
		DEF_COMPARE_MODE( LEQUAL ),
		DEF_COMPARE_MODE( GREATER ),
		DEF_COMPARE_MODE( NOTEQUAL ),
		DEF_COMPARE_MODE( GEQUAL ),
		DEF_COMPARE_MODE( ALWAYS )
	};
	static const uint			s_uCompareModesCount = COUNT_OF( s_aCompareModes );
	static char					s_aTemp[64];
#undef  DEF_COMPARE_MODE

	for (uint i = 0; i < s_uCompareModesCount; ++i) {
		if ( s_aCompareModes[i].eType == eType )
			return s_aCompareModes[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetCullMode(e_cull_mode::type eType)
{
	struct TCullMode
	{
		const char	*		pName;
		e_cull_mode::type	eType;
	};

#define DEF_CULL_MODE( _type )		{ TOSTRING( _type ), e_cull_mode::_type }
	static const TCullMode	s_aCullModes[] = {
		DEF_CULL_MODE( NONE ),
		DEF_CULL_MODE( BACK ),
		DEF_CULL_MODE( FRONT ),
		DEF_CULL_MODE( FRONT_AND_BACK ),
		DEF_CULL_MODE( FACE_CCW ),
		DEF_CULL_MODE( FACE_CW ),
		DEF_CULL_MODE( FACE_CCW_CULL_BACK ),
		DEF_CULL_MODE( FACE_CCW_CULL_FRONT ),
		DEF_CULL_MODE( FACE_CCW_CULL_FRONT_AND_BACK )
	};
	static const uint		s_uCullModesCount = COUNT_OF( s_aCullModes );
	static char				s_aTemp[64];
#undef  DEF_CULL_MODE

	for (uint i = 0; i < s_uCullModesCount; ++i) {
		if ( s_aCullModes[i].eType == eType )
			return s_aCullModes[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetProgramType(e_program::type eType)
{
	struct TProgType
	{
		const char	*			pName;
		e_program::type			eType;
	};
	
#define DEF_PROG_TYPE( _type )		{ TOSTRING( _type ), e_program::_type }
	static const TProgType	s_aProgTypes[] = {
		DEF_PROG_TYPE( UNTEXTURED ),
		DEF_PROG_TYPE( DIFFUSE ),
		DEF_PROG_TYPE( NORMAL ),
		DEF_PROG_TYPE( PARALLAX ),
		DEF_PROG_TYPE( DISPLACEMENT ),
		DEF_PROG_TYPE( DEPTH )
	};
	static const uint		s_uProgTypesCount = COUNT_OF( s_aProgTypes );
	static char				s_aTemp[64];
#undef DEF_PROG_TYPE

	for (uint i = 0; i < s_uProgTypesCount; ++i) {
		if ( s_aProgTypes[i].eType == eType )
			return s_aProgTypes[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetProgramData(e_program_data::type eType)
{
	struct TProgData
	{
		const char *			pName;
		e_program_data::type	eType;
	};

#define DEF_PROG_DATA( _type )		{ TOSTRING( _type ), e_program_data::_type }
	static const TProgData	s_aProgDataTypes[] = {
		DEF_PROG_DATA( UNKNOWN ),
		DEF_PROG_DATA( MATERIAL ),
		DEF_PROG_DATA( LIGHT ),
		DEF_PROG_DATA( SHADOW ),
		DEF_PROG_DATA( CAMERA ),
		DEF_PROG_DATA( POSTPROCESS_PARAMS ),
		DEF_PROG_DATA( SCELET_DATA ),
		DEF_PROG_DATA( BUILTIN_DATA )
	};
	static const uint		s_uProgDataCount = COUNT_OF( s_aProgDataTypes );
	static char				s_aTemp[64];
#undef  DEF_PROG_DATA

	for (uint i = 0; i < s_uProgDataCount; ++i) {
		if ( s_aProgDataTypes[i].eType == eType )
			return s_aProgDataTypes[i].pName;

	}
	return itoa( eType, s_aTemp, 16 );
}


const char * _GetRenderLayer(e_render_layer::type eType)
{
	struct TRenLayer
	{
		const char	*			pName;
		e_render_layer::type	eType;
	};

#define DEF_REN_LAYER( _type )		{ TOSTRING( _type ), e_render_layer::_type }
	static const TRenLayer	s_aRenLayers[] = {
		DEF_REN_LAYER( SINGLE_SHADOW_MAP ),
		DEF_REN_LAYER( LAYERED_SHADOW_MAP ),
		DEF_REN_LAYER( SHADOW_MAP_2 ),
		DEF_REN_LAYER( DEPTH_ONLY_0 ),
		DEF_REN_LAYER( DEPTH_ONLY_1 ),
		DEF_REN_LAYER( DEPTH_ONLY_2 ),
		DEF_REN_LAYER( BACKGROUND_0 ),
		DEF_REN_LAYER( BACKGROUND_1 ),
		DEF_REN_LAYER( BACKGROUND_2 ),
		DEF_REN_LAYER( OPAQUE_0 ),
		DEF_REN_LAYER( OPAQUE_1 ),
		DEF_REN_LAYER( OPAQUE_2 ),
		DEF_REN_LAYER( OPAQUE_3 ),
		DEF_REN_LAYER( OPAQUE_4 ),
		DEF_REN_LAYER( OPAQUE_5 ),
		DEF_REN_LAYER( OPAQUE_6 ),
		DEF_REN_LAYER( OPAQUE_7 ),
		DEF_REN_LAYER( OPAQUE_8 ),
		DEF_REN_LAYER( OPAQUE_9 ),
		DEF_REN_LAYER( OPAQUE_10 ),
		DEF_REN_LAYER( OPAQUE_11 ),
		DEF_REN_LAYER( OPAQUE_12 ),
		DEF_REN_LAYER( OPAQUE_13 ),
		DEF_REN_LAYER( OPAQUE_14 ),
		DEF_REN_LAYER( OPAQUE_15 ),
		DEF_REN_LAYER( FOREGROUND_0 ),
		DEF_REN_LAYER( FOREGROUND_1 ),
		DEF_REN_LAYER( FOREGROUND_2 ),
		DEF_REN_LAYER( EMISSION_0 ),
		DEF_REN_LAYER( EMISSION_1 ),
		DEF_REN_LAYER( EMISSION_2 ),
		DEF_REN_LAYER( TRANSLUCENT )
	};
	static const uint	s_uRenLayersCount = COUNT_OF( s_aRenLayers );
	static char			s_aTemp[64];
#undef DEF_REN_LAYER
	
	for (uint i = 0; i < s_uRenLayersCount; ++i) {
		if ( s_aRenLayers[i].eType == eType )
			return s_aRenLayers[i].pName;
	}
	return itoa( eType, s_aTemp, 16 );
}


void TMtrConverter::_BuildMtrPass(e_program::type eProgType, e_render_layer::type eLayer,
								  e_program_data::type eProgData, uint8 uLOD, const string &sUBOData,
								  const string &sTextures, const TGLRenderState &sRS, bool bRS)
{
	sData	<< "	object MaterialPass\n"
			<< "	{\n"
			<< "		type		= e_program." << _GetProgramType( eProgType ) << ";\n"
			<< "		data_type	= e_program_data." << _GetProgramData( eProgData ) << ";\n"
			<< "		layer		= e_render_layer." << _GetRenderLayer( eLayer ) << ";\n"
			<< "		rs_lock		= e_render_state_lock.NONE;\n"
			<< "		locked		= false;\n"
			<< "		lod			= " << uLOD << ";\n\n";

	if ( !sUBOData.Empty() )
	{
		sData
			<< "		data		= struct { \n"
			<< sUBOData
			<< "		}\n\n";
	}
	
	if ( !sTextures.Empty() )
	{
		sData
			<< "		textures	= array /*MaterialTexture*/ {\n"
			<< sTextures
			<< "		}\n\n";
	}

	if ( bRS )
	{
		sData
			<< "		render_state = object RenderState\n"
			<< "		{\n"
			<< "			blending		  = " << sRS.bBlending << ";\n";

		if ( sRS.bBlending ) {
		sData
			<< "			blend_src_rgb	  = e_blend_func." << _GetBlendFunc( sRS.eSrcRGB ) << ";\n"
			<< "			blend_src_alpha	  = e_blend_func." << _GetBlendFunc( sRS.eSrcAlpha ) << ";\n"
			<< "			blend_dst_rgb	  = e_blend_func." << _GetBlendFunc( sRS.eDstRGB ) << ";\n"
			<< "			blend_dst_alpha	  = e_blend_func." << _GetBlendFunc( sRS.eDstAlpha ) << ";\n"
			<< "			blend_mode_rgb	  = e_blend_equation." << _GetBlendEquation( sRS.eModeRGB ) << ";\n"
			<< "			blend_mode_alpha  = e_blend_equation." << _GetBlendEquation( sRS.eModeAlpha ) << ";\n\n";
		}

		sData
			<< "			color_mask		  = e_color_mask." << _GetColorMask( sRS.eColorMask ) << ";\n\n"
			<< "			depth_func		  = e_compare_mode." << _GetCompareMode( sRS.eDepthFunc ) << ";\n"
			<< "			depth_test		  = " << sRS.bDepthTest << ";\n"
			<< "			depth_write		  = " << sRS.bDepthWrite << ";\n\n";

		if ( sRS.bStencilTest ) {
		sData
			<< "			stencil_test	  = " << sRS.bStencilTest << ";\n"
			<< "			stencil_mask	  = " << sRS.uStencilMask << ";\n"
			<< "			stencil_func	  = e_compare_mode." << _GetCompareMode( sRS.eStencilFunc ) << ";\n"
			<< "			stencil_func_ref  = " << sRS.iStencilFuncRef << ";\n"
			<< "			stencil_func_mask = " << sRS.uStencilFuncMask << ";\n\n";
		}

		sData
			<< "			cull_mode		  = e_cull_mode." << _GetCullMode( sRS.eCullMode ) << ";\n"
			<< "		}\n"
			<< "	}\n";
	}
}